home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / term / extras / source / term-source.lha / termSound.c < prev    next >
C/C++ Source or Header  |  1995-02-07  |  24KB  |  1,181 lines

  1. /*
  2. **    termSound.c
  3. **
  4. **    Sound support routines
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Double buffering chunk size. */
  13.  
  14. #define BUFFER_SIZE    32768
  15.  
  16.     /* Maximum replay volume. */
  17.  
  18. #define MAX_VOLUME    64
  19.  
  20.     /* Stereo/channel sample type. */
  21.  
  22. typedef LONG        SampleType;
  23.  
  24.     /* Channel definitions. */
  25.  
  26. #define SAMPLE_LEFT    2
  27. #define SAMPLE_RIGHT    4
  28. #define SAMPLE_STEREO    6
  29.  
  30.     /* A fixed-point value, 16 bits to the left of
  31.      * the point and 16 to the right. A Fixed is a
  32.      * number of 2**16ths, i.e. 65536ths.
  33.      */
  34.  
  35. typedef LONG        Fixed;
  36.  
  37.     /* Unity = Fixed 1.0 = maximum volume */
  38.  
  39. #define Unity        0x10000L
  40.  
  41.     /* Sample compression modes. */
  42.  
  43. #define sCmpNone    0
  44. #define sCmpFibDelta    1
  45.  
  46.     /* The voice header. */
  47.  
  48. typedef struct
  49. {
  50.     ULONG    oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  51.         repeatHiSamples,    /* # samples in the high octave repeat part */
  52.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0 */
  53.     UWORD    samplesPerSec;        /* data sampling rate */
  54.     UBYTE    ctOctave,        /* # of octaves of waveforms */
  55.         sCompression;        /* data compression technique used */
  56.     Fixed    volume;            /* playback nominal volume from 0 to Unity
  57.                      * (full volume). Map this value into
  58.                      * the output hardware's dynamic range.
  59.                      */
  60. } Voice8Header;
  61.  
  62.     /* Double-buffering information. */
  63.  
  64. struct BufferInfo
  65. {
  66.     LONG    Size;
  67.     UBYTE    Buffer[BUFFER_SIZE];
  68. };
  69.  
  70.     /* Sound replay information. */
  71.  
  72. struct SoundInfo
  73. {
  74.     UBYTE         Name[MAX_FILENAME_LENGTH];
  75.  
  76.     ULONG         Rate,
  77.              Length,
  78.              Volume;
  79.  
  80.     APTR         SoundData;
  81.  
  82.     APTR         LeftData,
  83.              RightData;
  84.  
  85.     Object        *SoundObject;
  86.     struct timeval     SoundTime;
  87. };
  88.  
  89.     /* Local data. */
  90.  
  91. STATIC struct SignalSemaphore    *SoundSemaphore;
  92. STATIC struct SoundInfo        *SoundSlot[SOUND_COUNT];
  93.  
  94.     /* DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst):
  95.      *
  96.      *    Unpack Fibonacci-delta-encoded data.
  97.      */
  98.  
  99. STATIC VOID __regargs
  100. DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst)
  101. {
  102.     STATIC BYTE CodeToDelta[16] = { -34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21 };
  103.  
  104.     BYTE    Value = (BYTE)Src[1];
  105.     UBYTE    Code;
  106.  
  107.         /* Skip the header information. */
  108.  
  109.     Src    += 2;
  110.     Size    -= 2;
  111.  
  112.         /* Run down the chunk... */
  113.  
  114.     while(Size--)
  115.     {
  116.         Code = *Src++;
  117.  
  118.             /* Add the top nibble delta. */
  119.  
  120.         Value += CodeToDelta[Code >> 4];
  121.  
  122.         *Dst++ = Value;
  123.  
  124.             /* Add the bottom nibble delta. */
  125.  
  126.         Value += CodeToDelta[Code & 0xF];
  127.  
  128.         *Dst++ = Value;
  129.     }
  130. }
  131.  
  132.     /* FreeSound(struct SoundInfo *SoundInfo):
  133.      *
  134.      *    Free sound handle and associated data.
  135.      */
  136.  
  137. VOID __regargs
  138. FreeSound(struct SoundInfo *SoundInfo)
  139. {
  140.     if(SoundInfo -> SoundObject)
  141.         DisposeDTObject(SoundInfo -> SoundObject);
  142.     else
  143.         FreeVecPooled(SoundInfo -> SoundData);
  144.  
  145.     FreeVecPooled(SoundInfo);
  146. }
  147.  
  148.     /* LoadSound(STRPTR Name):
  149.      *
  150.      *    Load a sound file from disk.
  151.      */
  152.  
  153. struct SoundInfo * __regargs
  154. LoadSound(STRPTR Name,BYTE Warn)
  155. {
  156.     struct SoundInfo    *SoundInfo = NULL;
  157.     struct IFFHandle    *Handle;
  158.  
  159.         /* Allocate IFF handle for reading. */
  160.  
  161.     if(Handle = AllocIFF())
  162.     {
  163.             /* Open a standard DOS stream. */
  164.  
  165.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  166.         {
  167.                 /* Say it's a DOS stream. */
  168.  
  169.             InitIFFasDOS(Handle);
  170.  
  171.                 /* Open the file for reading. */
  172.  
  173.             if(!OpenIFF(Handle,IFFF_READ))
  174.             {
  175.                 LONG SoundStops[3 * 2] =
  176.                 {
  177.                     ID_8SVX,ID_VHDR,
  178.                     ID_8SVX,ID_CHAN,
  179.                     ID_8SVX,ID_BODY
  180.                 };
  181.  
  182.                     /* Mark the chunks to stop at. */
  183.  
  184.                 if(!StopChunks(Handle,SoundStops,3))
  185.                 {
  186.                     struct ContextNode    *Chunk;
  187.                     Voice8Header         Header;
  188.                     UBYTE             Compression;
  189.                     SampleType         Channel    = SAMPLE_STEREO;
  190.                     BYTE             SingleChannel    = TRUE;
  191.  
  192.                         /* Clear the voice header. */
  193.  
  194.                     memset(&Header,0,sizeof(Voice8Header));
  195.  
  196.                         /* Scan for data... */
  197.  
  198.                     while(!ParseIFF(Handle,IFFPARSE_SCAN))
  199.                     {
  200.                         Chunk = CurrentChunk(Handle);
  201.  
  202.                             /* What did we find? */
  203.  
  204.                         switch(Chunk -> cn_ID)
  205.                         {
  206.                                 /* Looks like the basic voice header. */
  207.  
  208.                             case ID_VHDR:
  209.  
  210.                                     /* Read the header. */
  211.  
  212.                                 if(ReadChunkRecords(Handle,&Header,MIN(Chunk -> cn_Size,sizeof(Voice8Header)),1) == 1)
  213.                                 {
  214.                                         /* Compression type supported? */
  215.  
  216.                                     if(Header . sCompression == sCmpNone || Header . sCompression == sCmpFibDelta)
  217.                                     {
  218.                                             /* Allocate the sound handle. */
  219.  
  220.                                         if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  221.                                         {
  222.                                                 /* Install the rate, volume and length. */
  223.  
  224.                                             SoundInfo -> Rate    = SysBase -> ex_EClockFrequency * 5 / Header . samplesPerSec;
  225.                                             SoundInfo -> Length    = Header . oneShotHiSamples ? Header . oneShotHiSamples : (Header . repeatHiSamples ? Header . repeatHiSamples : Header . samplesPerHiCycle);
  226.                                             SoundInfo -> Volume    = (SoundConfig . Volume * ((Header . volume * MAX_VOLUME) / Unity)) / 100;
  227.  
  228.                                                 /* Remember compression mode. */
  229.  
  230.                                             Compression        = Header . sCompression;
  231.                                         }
  232.                                     }
  233.                                 }
  234.  
  235.                                 break;
  236.  
  237.                                 /* Looks like sound channel information. */
  238.  
  239.                             case ID_CHAN:
  240.  
  241.                                     /* Do we have a handle to manage it? */
  242.  
  243.                                 if(SoundInfo)
  244.                                 {
  245.                                         /* Read the channel information. */
  246.  
  247.                                     if(ReadChunkRecords(Handle,&Channel,MIN(Chunk -> cn_Size,sizeof(SampleType)),1) == 1)
  248.                                     {
  249.                                             /* Stereo sound file? */
  250.  
  251.                                         if(Channel == SAMPLE_STEREO)
  252.                                             SingleChannel = FALSE;
  253.                                     }
  254.                                     else
  255.                                     {
  256.                                         FreeVecPooled(SoundInfo);
  257.  
  258.                                         SoundInfo = NULL;
  259.                                     }
  260.                                 }
  261.  
  262.                                 break;
  263.  
  264.                                 /* Looks like the sound body data. */
  265.  
  266.                             case ID_BODY:
  267.  
  268.                                     /* Do we have sound handle to manage it? */
  269.  
  270.                                 if(SoundInfo)
  271.                                 {
  272.                                     BYTE Success = FALSE;
  273.  
  274.                                     if(!SoundInfo -> Length)
  275.                                         SoundInfo -> Length = Chunk -> cn_Size;
  276.  
  277.                                         /* Uncompressed raw data? */
  278.  
  279.                                     if(Compression == sCmpNone)
  280.                                     {
  281.                                         ULONG Wanted;
  282.  
  283.                                         if(Channel == SAMPLE_STEREO && !SingleChannel)
  284.                                         {
  285.                                             Wanted = SoundInfo -> Length * 2;
  286.  
  287.                                             if(Wanted > Chunk -> cn_Size)
  288.                                             {
  289.                                                 SoundInfo -> Length /= 2;
  290.  
  291.                                                 Wanted = SoundInfo -> Length * 2;
  292.                                             }
  293.                                         }
  294.                                         else
  295.                                             Wanted = SoundInfo -> Length;
  296.  
  297.                                         if(Chunk -> cn_Size >= Wanted)
  298.                                         {
  299.                                                 /* Allocate a buffer. */
  300.  
  301.                                             if(SoundInfo -> SoundData = AllocVecPooled(Wanted,MEMF_ANY))
  302.                                             {
  303.                                                     /* Read the data. */
  304.  
  305.                                                 if(ReadChunkRecords(Handle,SoundInfo -> SoundData,Wanted,1) == 1)
  306.                                                     Success = TRUE;
  307.                                                 else
  308.                                                     FreeVecPooled(SoundInfo -> SoundData);
  309.                                             }
  310.                                         }
  311.                                     }
  312.                                     else
  313.                                     {
  314.                                         ULONG Wanted;
  315.  
  316.                                         if(Channel == SAMPLE_STEREO && !SingleChannel)
  317.                                         {
  318.                                             Wanted = SoundInfo -> Length + 4;
  319.  
  320.                                             if(Wanted > Chunk -> cn_Size)
  321.                                             {
  322.                                                 SoundInfo -> Length /= 2;
  323.  
  324.                                                 Wanted = SoundInfo -> Length * 2 + 4;
  325.  
  326.                                                 SingleChannel = TRUE;
  327.                                             }
  328.                                         }
  329.                                         else
  330.                                             Wanted = SoundInfo -> Length / 2 + 2;
  331.  
  332.                                         if(Chunk -> cn_Size >= Wanted)
  333.                                         {
  334.                                             UBYTE    *TempBuffer;
  335.  
  336.                                                 /* Allocate a temporary decompression buffer. */
  337.  
  338.                                             if(TempBuffer = (UBYTE *)AllocVecPooled(Chunk -> cn_Size,MEMF_ANY))
  339.                                             {
  340.                                                     /* Read the compressed data. */
  341.  
  342.                                                 if(ReadChunkRecords(Handle,TempBuffer,Chunk -> cn_Size,1) == 1)
  343.                                                 {
  344.                                                     ULONG Length = SoundInfo -> Length;
  345.  
  346.                                                         /* Allocate space for the uncompressed data. */
  347.  
  348.                                                     if(SoundInfo -> SoundData = AllocVecPooled(Length * 2,MEMF_ANY))
  349.                                                     {
  350.                                                             /* Stereo sound file? */
  351.  
  352.                                                         if(!SingleChannel && Channel == SAMPLE_STEREO)
  353.                                                         {
  354.                                                             UBYTE *Data = SoundInfo -> SoundData;
  355.  
  356.                                                                 /* Unpack the stereo sound. */
  357.  
  358.                                                             DeltaUnpack(TempBuffer,                 Length / 2 + 2,Data);
  359.                                                             DeltaUnpack(TempBuffer + Length / 2 + 2,Length / 2 + 2,Data + Length);
  360.                                                         }
  361.                                                         else
  362.                                                         {
  363.                                                                 /* Unpack the mono sound. */
  364.  
  365.                                                             DeltaUnpack(TempBuffer,Length / 2 + 2,SoundInfo -> SoundData);
  366.                                                         }
  367.  
  368.                                                         Success = TRUE;
  369.                                                     }
  370.                                                 }
  371.  
  372.                                                 FreeVecPooled(TempBuffer);
  373.                                             }
  374.                                         }
  375.                                     }
  376.  
  377.                                     if(!Success)
  378.                                     {
  379.                                         FreeVecPooled(SoundInfo);
  380.  
  381.                                         SoundInfo = NULL;
  382.                                     }
  383.                                 }
  384.  
  385.                                 break;
  386.                         }
  387.                     }
  388.  
  389.                         /* Did we get what we wanted? */
  390.  
  391.                     if(SoundInfo)
  392.                     {
  393.                             /* Any sound data allocated? */
  394.  
  395.                         if(SoundInfo -> SoundData)
  396.                         {
  397.                             UBYTE *Data = SoundInfo -> SoundData;
  398.  
  399.                                 /* Which kind of sound file did
  400.                                  * we read?
  401.                                  */
  402.  
  403.                             switch(Channel)
  404.                             {
  405.                                     /* Left channel only. */
  406.  
  407.                                 case SAMPLE_LEFT:
  408.  
  409.                                     SoundInfo -> LeftData = Data;
  410.                                     break;
  411.  
  412.                                     /* Right channel only. */
  413.  
  414.                                 case SAMPLE_RIGHT:
  415.  
  416.                                     SoundInfo -> RightData = Data;
  417.                                     break;
  418.  
  419.                                     /* Two stereo channels. */
  420.  
  421.                                 case SAMPLE_STEREO:
  422.  
  423.                                         /* One sound mapped to two voices. */
  424.  
  425.                                     if(SingleChannel)
  426.                                         SoundInfo -> LeftData = SoundInfo -> RightData = Data;
  427.                                     else
  428.                                     {
  429.                                             /* Split the voice data. */
  430.  
  431.                                         SoundInfo -> LeftData    = Data;
  432.                                         SoundInfo -> RightData    = Data + SoundInfo -> Length;
  433.                                     }
  434.  
  435.                                     break;
  436.                             }
  437.                         }
  438.                         else
  439.                         {
  440.                             FreeVecPooled(SoundInfo);
  441.  
  442.                             SoundInfo = NULL;
  443.                         }
  444.                     }
  445.                 }
  446.  
  447.                 CloseIFF(Handle);
  448.             }
  449.  
  450.             Close(Handle -> iff_Stream);
  451.         }
  452.  
  453.         FreeIFF(Handle);
  454.     }
  455.  
  456.         /* Successful? */
  457.  
  458.     if(SoundInfo)
  459.         strcpy(SoundInfo -> Name,Name);
  460.     else
  461.     {
  462.         if(DataTypesBase)
  463.         {
  464.             Object *Sound;
  465.  
  466.             if(Sound = NewDTObject(Name,
  467.                 DTA_SourceType,    DTST_FILE,
  468.                 DTA_GroupID,    GID_SOUND,
  469.                 SDTA_Volume,    64,
  470.                 SDTA_Cycles,    1,
  471.             TAG_DONE))
  472.             {
  473.                 ULONG             SampleLength    = 0;
  474.                 struct VoiceHeader    *Header        = NULL;
  475.  
  476.                 if(GetDTAttrs(Sound,
  477.                     SDTA_SampleLength,    &SampleLength,
  478.                     SDTA_VoiceHeader,    &Header,
  479.                 TAG_DONE) == 2)
  480.                 {
  481.                     if(SampleLength && Header)
  482.                     {
  483.                         ULONG Secs,Micro,Period;
  484.  
  485.                         Period    = Header -> vh_SamplesPerSec;
  486.  
  487.                         Secs    = SampleLength / Period;
  488.                         Micro    = (1000000 / Period) * (SampleLength % Period);
  489.  
  490.                         if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  491.                         {
  492.                             strcpy(SoundInfo -> Name,Name);
  493.  
  494.                             SoundInfo -> SoundObject        = Sound;
  495.                             SoundInfo -> SoundTime . tv_secs    = Secs;
  496.                             SoundInfo -> SoundTime . tv_micro    = Micro;
  497.  
  498.                             return(SoundInfo);
  499.                         }
  500.                     }
  501.                 }
  502.  
  503.                 DisposeDTObject(Sound);
  504.             }
  505.         }
  506.  
  507.         if(Warn)
  508.             MyEasyRequest(Window,LocaleString(MSG_TERMSOUND_COULD_NOT_LOAD_SOUND_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Name);
  509.     }
  510.  
  511.     return(SoundInfo);
  512. }
  513.  
  514.     /* ReplaySound():
  515.      *
  516.      *    Replay sound with given information (doubly-buffered).
  517.      */
  518.  
  519. STATIC VOID __inline
  520. ReplaySound(struct SoundInfo *SoundInfo,struct IOAudio *SoundControlRequest,struct IOAudio *SoundRequestLeft,struct IOAudio *SoundRequestRight,struct BufferInfo *BufferInfo)
  521. {
  522.     UBYTE    *Left    = SoundInfo -> LeftData,
  523.         *Right    = SoundInfo -> RightData;
  524.     ULONG     Size    = SoundInfo -> Length,Length;
  525.     WORD     Base    = 0;
  526.  
  527.     Length = MIN(BUFFER_SIZE,Size);
  528.  
  529.     Size -= Length;
  530.  
  531.         /* Left channel available? */
  532.  
  533.     if(!(((ULONG)SoundRequestLeft -> ioa_Request . io_Unit) & (LEFT0F | LEFT1F)))
  534.         Left = NULL;
  535.  
  536.         /* Right channel available? */
  537.  
  538.     if(!(((ULONG)SoundRequestRight -> ioa_Request . io_Unit) & (RIGHT0F | RIGHT1F)))
  539.         Right = NULL;
  540.  
  541.         /* Fill up left buffer. */
  542.  
  543.     if(Left)
  544.     {
  545.         CopyMem(Left,BufferInfo[Base] . Buffer,Length);
  546.  
  547.         BufferInfo[Base] . Size = Length;
  548.  
  549.         Left += Length;
  550.     }
  551.  
  552.         /* Fill up right buffer. */
  553.  
  554.     if(Right)
  555.     {
  556.         CopyMem(Right,BufferInfo[Base + 2] . Buffer,Length);
  557.  
  558.         BufferInfo[Base + 2] . Size = Length;
  559.  
  560.         Right += Length;
  561.     }
  562.  
  563.         /* Process sound data. */
  564.  
  565.     do
  566.     {
  567.             /* Block both channels. */
  568.  
  569.         SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  570.  
  571.         SendIO(SoundControlRequest);
  572.         WaitIO(SoundControlRequest);
  573.  
  574.             /* Any data for the left channel? */
  575.  
  576.         if(Left)
  577.         {
  578.             SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  579.             SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  580.             SoundRequestLeft -> ioa_Period            = SoundInfo -> Rate;
  581.             SoundRequestLeft -> ioa_Volume            = SoundInfo -> Volume;
  582.             SoundRequestLeft -> ioa_Cycles            = 1;
  583.             SoundRequestLeft -> ioa_Data            = BufferInfo[Base] . Buffer;
  584.             SoundRequestLeft -> ioa_Length            = BufferInfo[Base] . Size;
  585.  
  586.                 /* Get the left channel going. */
  587.  
  588.             BeginIO(SoundRequestLeft);
  589.         }
  590.  
  591.             /* Any data for the right channel? */
  592.  
  593.         if(Right)
  594.         {
  595.             SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  596.             SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  597.             SoundRequestRight -> ioa_Period            = SoundInfo -> Rate;
  598.             SoundRequestRight -> ioa_Volume            = SoundInfo -> Volume;
  599.             SoundRequestRight -> ioa_Cycles            = 1;
  600.             SoundRequestRight -> ioa_Data            = BufferInfo[Base + 2] . Buffer;
  601.             SoundRequestRight -> ioa_Length            = BufferInfo[Base + 2] . Size;
  602.  
  603.                 /* Get the right channel going. */
  604.  
  605.             BeginIO(SoundRequestRight);
  606.         }
  607.  
  608.             /* Start up both channels synchronously... */
  609.  
  610.         SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  611.  
  612.         SendIO(SoundControlRequest);
  613.         WaitIO(SoundControlRequest);
  614.  
  615.             /* Grab the other buffers. */
  616.  
  617.         Base ^= 1;
  618.  
  619.             /* Still any data left? */
  620.  
  621.         if(Size)
  622.         {
  623.                 /* Cut off the next slice. */
  624.  
  625.             Length = MIN(BUFFER_SIZE,Size);
  626.  
  627.             Size -= Length;
  628.  
  629.                 /* Left channel available? */
  630.  
  631.             if(Left)
  632.             {
  633.                 CopyMem(Left,BufferInfo[Base] . Buffer,Length);
  634.  
  635.                 BufferInfo[Base] . Size = Length;
  636.  
  637.                 Left += Length;
  638.             }
  639.  
  640.                 /* Right channel available? */
  641.  
  642.             if(Right)
  643.             {
  644.                 CopyMem(Right,BufferInfo[Base + 2] . Buffer,Length);
  645.  
  646.                 BufferInfo[Base + 2] . Size = Length;
  647.  
  648.                 Right += Length;
  649.             }
  650.  
  651.                 /* Last slice eaten? */
  652.  
  653.             if(!Size)
  654.             {
  655.                     /* Wait for sounds to terminate. */
  656.  
  657.                 if(Left)
  658.                     WaitIO(SoundRequestLeft);
  659.  
  660.                 if(Right)
  661.                     WaitIO(SoundRequestRight);
  662.  
  663.                     /* Block both channels. */
  664.  
  665.                 SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  666.  
  667.                 SendIO(SoundControlRequest);
  668.                 WaitIO(SoundControlRequest);
  669.  
  670.                     /* Any data for the left channel? */
  671.  
  672.                 if(Left)
  673.                 {
  674.                     SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  675.                     SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  676.                     SoundRequestLeft -> ioa_Period            = SoundInfo -> Rate;
  677.                     SoundRequestLeft -> ioa_Volume            = SoundInfo -> Volume;
  678.                     SoundRequestLeft -> ioa_Cycles            = 1;
  679.                     SoundRequestLeft -> ioa_Data            = BufferInfo[Base] . Buffer;
  680.                     SoundRequestLeft -> ioa_Length            = BufferInfo[Base] . Size;
  681.  
  682.                         /* Get the left channel going. */
  683.  
  684.                     BeginIO(SoundRequestLeft);
  685.                 }
  686.  
  687.                     /* Any data for the right channel? */
  688.  
  689.                 if(Right)
  690.                 {
  691.                     SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  692.                     SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  693.                     SoundRequestRight -> ioa_Period            = SoundInfo -> Rate;
  694.                     SoundRequestRight -> ioa_Volume            = SoundInfo -> Volume;
  695.                     SoundRequestRight -> ioa_Cycles            = 1;
  696.                     SoundRequestRight -> ioa_Data            = BufferInfo[Base + 2] . Buffer;
  697.                     SoundRequestRight -> ioa_Length            = BufferInfo[Base + 2] . Size;
  698.  
  699.                         /* Get the right channel going. */
  700.  
  701.                     BeginIO(SoundRequestRight);
  702.                 }
  703.  
  704.                     /* Start up both channels synchronously... */
  705.  
  706.                 SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  707.  
  708.                 SendIO(SoundControlRequest);
  709.                 WaitIO(SoundControlRequest);
  710.             }
  711.         }
  712.  
  713.             /* Wait for sounds to terminate. */
  714.  
  715.         if(Left)
  716.             WaitIO(SoundRequestLeft);
  717.  
  718.         if(Right)
  719.             WaitIO(SoundRequestRight);
  720.     }
  721.     while(Size);
  722. }
  723.  
  724.     /* PlaySound(struct SoundInfo *SoundInfo):
  725.      *
  726.      *    Replay a sound.
  727.      */
  728.  
  729. VOID __regargs
  730. PlaySound(struct SoundInfo *SoundInfo)
  731. {
  732.     if(SoundInfo -> SoundObject)
  733.     {
  734.         struct MsgPort *TimePort;
  735.  
  736.         if(TimePort = CreateMsgPort())
  737.         {
  738.             struct timerequest *TimeRequest;
  739.  
  740.             if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  741.             {
  742.                 if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  743.                 {
  744.                     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  745.                     TimeRequest -> tr_time            = SoundInfo -> SoundTime;
  746.  
  747.                     SetSignal(0,PORTMASK(TimePort));
  748.  
  749.                     SendIO(TimeRequest);
  750.  
  751.                     DoMethod(SoundInfo -> SoundObject,DTM_TRIGGER,NULL,STM_PLAY,NULL);
  752.  
  753.                     WaitIO(TimeRequest);
  754.  
  755.                     CloseDevice(TimeRequest);
  756.                 }
  757.  
  758.                 DeleteIORequest(TimeRequest);
  759.             }
  760.  
  761.             DeleteMsgPort(TimePort);
  762.         }
  763.     }
  764.     else
  765.     {
  766.         struct BufferInfo *BufferInfo;
  767.  
  768.             /* Allocate sound buffers. */
  769.  
  770.         if(BufferInfo = (struct BufferInfo *)AllocVec(4 * sizeof(struct BufferInfo),MEMF_CHIP))
  771.         {
  772.             struct MsgPort *SoundPort;
  773.  
  774.                 /* Allocate an io replyport. */
  775.  
  776.             if(SoundPort = CreateMsgPort())
  777.             {
  778.                 struct IOAudio *SoundControlRequest;
  779.  
  780.                     /* Allocate the big sound control request. */
  781.  
  782.                 if(SoundControlRequest = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  783.                 {
  784.                     struct IOAudio *SoundRequestLeft;
  785.  
  786.                         /* Allocate the left channel sound request. */
  787.  
  788.                     if(SoundRequestLeft = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  789.                     {
  790.                         struct IOAudio *SoundRequestRight;
  791.  
  792.                             /* Allocate the right channel sound request. */
  793.  
  794.                         if(SoundRequestRight = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  795.                         {
  796.                             STATIC UBYTE TwoChannels[] =
  797.                             {
  798.                                 LEFT0F | RIGHT0F,
  799.                                 LEFT0F | RIGHT1F,
  800.                                 LEFT1F | RIGHT0F,
  801.                                 LEFT1F | RIGHT1F
  802.                             };
  803.  
  804.                             STATIC UBYTE LeftChannel[] =
  805.                             {
  806.                                 LEFT0F,
  807.                                 LEFT1F
  808.                             };
  809.  
  810.                             STATIC UBYTE RightChannel[] =
  811.                             {
  812.                                 RIGHT0F,
  813.                                 RIGHT1F
  814.                             };
  815.  
  816.                             UBYTE    *AllocationMap;
  817.                             LONG     AllocationSize;
  818.  
  819.                                 /* Determine the correct channel
  820.                                  * allocation map.
  821.                                  */
  822.  
  823.                             if(SoundInfo -> LeftData)
  824.                             {
  825.                                 if(SoundInfo -> RightData)
  826.                                 {
  827.                                     AllocationMap    = TwoChannels;
  828.                                     AllocationSize    = sizeof(TwoChannels);
  829.                                 }
  830.                                 else
  831.                                 {
  832.                                     AllocationMap    = LeftChannel;
  833.                                     AllocationSize    = sizeof(LeftChannel);
  834.                                 }
  835.                             }
  836.                             else
  837.                             {
  838.                                 AllocationMap    = RightChannel;
  839.                                 AllocationSize    = sizeof(RightChannel);
  840.                             }
  841.  
  842.                                 /* Set up for sound channel allocation. */
  843.  
  844.                             SoundControlRequest -> ioa_Request . io_Message . mn_Node . ln_Pri    = 127;
  845.                             SoundControlRequest -> ioa_Request . io_Command                = ADCMD_ALLOCATE;
  846.                             SoundControlRequest -> ioa_Request . io_Flags                = ADIOF_NOWAIT | ADIOF_PERVOL;
  847.                             SoundControlRequest -> ioa_Data                        = AllocationMap;
  848.                             SoundControlRequest -> ioa_Length                    = AllocationSize;
  849.  
  850.                                 /* Open audio.device, allocating the sound
  851.                                  * channels on the fly.
  852.                                  */
  853.  
  854.                             if(!OpenDevice(AUDIONAME,NULL,SoundControlRequest,NULL))
  855.                             {
  856.                                     /* Clone the sound control request. */
  857.  
  858.                                 CopyMem(SoundControlRequest,SoundRequestLeft,    sizeof(struct IOAudio));
  859.                                 CopyMem(SoundControlRequest,SoundRequestRight,    sizeof(struct IOAudio));
  860.  
  861.                                     /* Separate the channels. */
  862.  
  863.                                 SoundRequestLeft  -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestLeft  -> ioa_Request . io_Unit & (LEFT0F  | LEFT1F));
  864.                                 SoundRequestRight -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestRight -> ioa_Request . io_Unit & (RIGHT0F | RIGHT1F));
  865.  
  866.                                     /* Replay the sound... */
  867.  
  868.                                 ReplaySound(SoundInfo,SoundControlRequest,SoundRequestLeft,SoundRequestRight,BufferInfo);
  869.  
  870.                                     /* Do the big cleanup. */
  871.  
  872.                                 CloseDevice(SoundControlRequest);
  873.                             }
  874.  
  875.                             DeleteIORequest(SoundRequestRight);
  876.                         }
  877.  
  878.                         DeleteIORequest(SoundRequestLeft);
  879.                     }
  880.  
  881.                     DeleteIORequest(SoundControlRequest);
  882.                 }
  883.  
  884.                 DeleteMsgPort(SoundPort);
  885.             }
  886.  
  887.             FreeVec(BufferInfo);
  888.         }
  889.     }
  890. }
  891.  
  892.     /* SoundLoad(WORD Sound,BYTE Warn):
  893.      *
  894.      *    Loads or frees a sound slot.
  895.      */
  896.  
  897. STATIC BYTE __regargs
  898. SoundLoad(WORD Sound,BYTE Warn)
  899. {
  900.     struct SoundInfo    **Info = &SoundSlot[Sound];
  901.     STRPTR            Name;
  902.     BYTE            Success = FALSE;
  903.  
  904.         /* Which sound file name are we to pick? */
  905.  
  906.     switch(Sound)
  907.     {
  908.         case SOUND_BELL:
  909.  
  910.             Name = SoundConfig . BellFile;
  911.             break;
  912.  
  913.         case SOUND_CONNECT:
  914.  
  915.             Name = SoundConfig . ConnectFile;
  916.             break;
  917.  
  918.         case SOUND_DISCONNECT:
  919.  
  920.             Name = SoundConfig . DisconnectFile;
  921.             break;
  922.  
  923.         case SOUND_GOODTRANSFER:
  924.  
  925.             Name = SoundConfig . GoodTransferFile;
  926.             break;
  927.  
  928.         case SOUND_BADTRANSFER:
  929.  
  930.             Name = SoundConfig . BadTransferFile;
  931.             break;
  932.  
  933.         case SOUND_RING:
  934.  
  935.             Name = SoundConfig . RingFile;
  936.             break;
  937.  
  938.         case SOUND_VOICE:
  939.  
  940.             Name = SoundConfig . VoiceFile;
  941.             break;
  942.  
  943.         case SOUND_ERROR:
  944.  
  945.             Name = SoundConfig . ErrorNotifyFile;
  946.             break;
  947.     }
  948.  
  949.         /* Is a file name available? */
  950.  
  951.     if(Name[0])
  952.     {
  953.             /* Sound slot already initialized? */
  954.  
  955.         if(*Info)
  956.         {
  957.                 /* Did the file name change? */
  958.  
  959.             if(Stricmp((*Info) -> Name,Name))
  960.             {
  961.                     /* Free the sound slot. */
  962.  
  963.                 FreeSound(*Info);
  964.  
  965.                     /* Try to load the sound slot. */
  966.  
  967.                 if(*Info = LoadSound(Name,Warn))
  968.                 {
  969.                         /* Remember the file name. */
  970.  
  971.                     strcpy((*Info) -> Name,Name);
  972.  
  973.                     Success = TRUE;
  974.                 }
  975.             }
  976.             else
  977.                 Success = TRUE;
  978.         }
  979.         else
  980.         {
  981.                 /* Try to load the sound slot. */
  982.  
  983.             if(*Info = LoadSound(Name,Warn))
  984.             {
  985.                     /* Remember the file name. */
  986.  
  987.                 strcpy((*Info) -> Name,Name);
  988.  
  989.                 Success = TRUE;
  990.             }
  991.         }
  992.     }
  993.     else
  994.     {
  995.             /* Does the slot still contain any sound? */
  996.  
  997.         if(*Info)
  998.         {
  999.                 /* Free the slot. */
  1000.  
  1001.             FreeSound(*Info);
  1002.  
  1003.             *Info = NULL;
  1004.         }
  1005.  
  1006.         Success = TRUE;
  1007.     }
  1008.  
  1009.     return(Success);
  1010. }
  1011.  
  1012.     /* SoundServer(VOID):
  1013.      *
  1014.      *    Replay a sound.
  1015.      */
  1016.  
  1017. STATIC VOID __saveds
  1018. SoundServer(VOID)
  1019. {
  1020.     LONG Sound = (LONG)SysBase -> ThisTask -> tc_UserData;
  1021.  
  1022.         /* Get exclusive access to the sound slots. */
  1023.  
  1024.     ObtainSemaphore(SoundSemaphore);
  1025.  
  1026.         /* Replay the sound. */
  1027.  
  1028.     PlaySound(SoundSlot[Sound]);
  1029.  
  1030.     Forbid();
  1031.  
  1032.         /* Release access to the sound slots. */
  1033.  
  1034.     ReleaseSemaphore(SoundSemaphore);
  1035.  
  1036.         /* Remove ourselves. */
  1037.  
  1038.     RemTask(NULL);
  1039. }
  1040.  
  1041.     /* SoundExit():
  1042.      *
  1043.      *    Free allocated sound resources.
  1044.      */
  1045.  
  1046. VOID
  1047. SoundExit()
  1048. {
  1049.     WORD i;
  1050.  
  1051.         /* Access semaphore available? */
  1052.  
  1053.     if(SoundSemaphore)
  1054.     {
  1055.         ObtainSemaphore(SoundSemaphore);
  1056.  
  1057.         ReleaseSemaphore(SoundSemaphore);
  1058.  
  1059.         FreeVecPooled(SoundSemaphore);
  1060.  
  1061.         SoundSemaphore = NULL;
  1062.     }
  1063.  
  1064.         /* Free the slots. */
  1065.  
  1066.     for(i = 0 ; i < SOUND_COUNT ; i++)
  1067.     {
  1068.         if(SoundSlot[i])
  1069.         {
  1070.             FreeSound(SoundSlot[i]);
  1071.  
  1072.             SoundSlot[i] = NULL;
  1073.         }
  1074.     }
  1075. }
  1076.  
  1077.     /* SoundInit():
  1078.      *
  1079.      *    Allocate resources required for sound replaying.
  1080.      */
  1081.  
  1082. VOID
  1083. SoundInit()
  1084. {
  1085.         /* Sound access semaphore available? */
  1086.  
  1087.     if(SoundSemaphore)
  1088.     {
  1089.         ObtainSemaphore(SoundSemaphore);
  1090.         ReleaseSemaphore(SoundSemaphore);
  1091.     }
  1092.     else
  1093.     {
  1094.         if(SoundSemaphore = (struct SignalSemaphore *)AllocVecPooled(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  1095.             InitSemaphore(SoundSemaphore);
  1096.     }
  1097.  
  1098.         /* Preload sounds if necessary. */
  1099.  
  1100.     if(SoundSemaphore && SoundConfig . Preload)
  1101.     {
  1102.         WORD i;
  1103.  
  1104.         for(i = 0 ; i < SOUND_COUNT ; i++)
  1105.             SoundLoad(i,TRUE);
  1106.     }
  1107. }
  1108.  
  1109.     /* SoundPlay(WORD Sound):
  1110.      *
  1111.      *    Play a certain sound slot.
  1112.      */
  1113.  
  1114. VOID __regargs
  1115. SoundPlay(WORD Sound)
  1116. {
  1117.         /* Sound access semaphore available? */
  1118.  
  1119.     if(SoundSemaphore)
  1120.     {
  1121.         if(SoundConfig . Volume)
  1122.         {
  1123.                 /* Check to see if we are currently playing a
  1124.                  * sound.
  1125.                  */
  1126.  
  1127.             if(!AttemptSemaphore(SoundSemaphore))
  1128.                 return;
  1129.             else
  1130.                 ReleaseSemaphore(SoundSemaphore);
  1131.  
  1132.                 /* Release any other sound if necessary. */
  1133.  
  1134.             if(!SoundConfig . Preload)
  1135.             {
  1136.                 WORD i;
  1137.  
  1138.                 for(i = 0 ; i < SOUND_COUNT ; i++)
  1139.                 {
  1140.                     if(i != Sound && SoundSlot[i])
  1141.                     {
  1142.                         FreeSound(SoundSlot[i]);
  1143.  
  1144.                         SoundSlot[i] = NULL;
  1145.                     }
  1146.                 }
  1147.             }
  1148.  
  1149.                 /* Load the sound slot. */
  1150.  
  1151.             SoundLoad(Sound,FALSE);
  1152.  
  1153.                 /* Slot filled? */
  1154.  
  1155.             if(SoundSlot[Sound])
  1156.             {
  1157.                 struct Task    *SoundTask;
  1158.                 LONG         Pri = ThisProcess -> pr_Task . tc_Node . ln_Pri + 10;
  1159.  
  1160.                     /* Priority raised, check for limit. */
  1161.  
  1162.                 if(Pri > 127)
  1163.                     Pri = 127;
  1164.  
  1165.                 Forbid();
  1166.  
  1167.                     /* Fire off the sound server task. */
  1168.  
  1169.                 if(SoundTask = CreateTask("term Sound Task",Pri,SoundServer,4096))
  1170.                     SoundTask -> tc_UserData = (APTR)Sound;
  1171.  
  1172.                 Permit();
  1173.             }
  1174.             else
  1175.                 Beep();
  1176.         }
  1177.     }
  1178.     else
  1179.         Beep();
  1180. }
  1181.